﻿using SerialCommunication.Model;
using System;
using System.IO.Ports;
using System.Threading;

namespace SerialCommunication.Common.SerialPorts
{
    #region 委托事件
    /// <summary>
    /// 串口状态
    /// </summary>
    /// <param name="Status"></param>
    public delegate void StatusEvent(bool Status);
    /// <summary>
    /// 数据接收
    /// </summary>
    /// <param name="Data"></param>
    public delegate void DataReceived(string Data);
    /// <summary>
    /// 接收结果委托
    /// </summary>
    /// <param name="StrWeight"></param>
    public delegate void ResultReceived(string StrResult);
    /// <summary>
    /// 接收串口原始委托
    /// </summary>
    /// <param name="OrginData"></param>
    public delegate void OrginDataReceived(string OrginData);
    #endregion

    public class ScalesSerialPort : IDisposable
    {
        #region 参数
        private static readonly SynchronizationContext DefaultSynchronizationContext = new SynchronizationContext();
        private readonly SynchronizationContext _synchronizationContext;

        private static SerialPorter _DefaultSerialPort = new SerialPorter(new SerialPort());
        private SerialPorter _CurrentSerialPort;

        public StatusEvent StatusEvent;
        public OrginDataReceived orginDataReceived;
        public ResultReceived resultReceived;
        #endregion

        #region 构造函数
        public ScalesSerialPort() : this(_DefaultSerialPort)
        {

        }

        public ScalesSerialPort(SerialPort SerialPort) : this(new SerialPorter(SerialPort))
        {

        }

        private ScalesSerialPort(SerialPorter SerialPort)
        {
            _synchronizationContext = SynchronizationContext.Current ?? DefaultSynchronizationContext;
            _CurrentSerialPort = SerialPort;
            _CurrentSerialPort.OrginDataReceived += _serialPort_DataReceived;
            _CurrentSerialPort.resultReceived += _serialPort_ResultReceived;
            _CurrentSerialPort.StatusEvent += _serialPort_StatusEvent;
        }
        #endregion

        #region 初始化
        private void _serialPort_DataReceived(string OrginData)
        {
            _synchronizationContext.Post((arg) =>
            {
                if (orginDataReceived != null)
                    orginDataReceived(OrginData);
            }, null);

        }

        private void _serialPort_ResultReceived(string StrWeight)
        {
            _synchronizationContext.Post((arg) =>
            {
                if (resultReceived != null)
                {
                    resultReceived(StrWeight);
                }
            }, null);
        }

        public void _serialPort_StatusEvent(bool Status)
        {
            _synchronizationContext.Post((arg) =>
            {
                if (StatusEvent != null)
                    StatusEvent(Status);
            }, null);
        }
        #endregion

        #region 方法
        /// <summary>
        /// 串口配置
        /// </summary>
        public void SetConfig(SerialPortSetting setting)
        {
            _CurrentSerialPort.SetConfig(_CurrentSerialPort.SerialPort, setting);
        }
        /// <summary>
        /// 串口状态
        /// </summary>
        public bool IsOpen
        {
            get
            {
                return _CurrentSerialPort.SerialPort.IsOpen;
            }
        }
        /// <summary>
        /// 串口名称
        /// </summary>
        public string PortName
        {
            get { return _CurrentSerialPort.SerialPort.PortName; }
        }
        /// <summary>
        /// 打开串口
        /// </summary>
        public void Open()
        {
            try
            {
                if (!_CurrentSerialPort.SerialPort.IsOpen)
                    _CurrentSerialPort.SerialPort.Open();
            }
            catch
            {
                throw;
            }
            finally
            {

                if (_CurrentSerialPort.StatusEvent != null)
                    _CurrentSerialPort.StatusEvent(_CurrentSerialPort.SerialPort.IsOpen);
            }
        }
        /// <summary>
        /// 关闭串口
        /// </summary>
        public void Close()
        {
            try
            {
                _CurrentSerialPort.SerialPort.Close();
            }
            catch
            {
                throw;
            }
            finally
            {
                if (_CurrentSerialPort.StatusEvent != null)
                    _CurrentSerialPort.StatusEvent(_CurrentSerialPort.SerialPort.IsOpen);
            }
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            _CurrentSerialPort.OrginDataReceived -= _serialPort_DataReceived;
            _CurrentSerialPort.resultReceived -= _serialPort_ResultReceived;
            _CurrentSerialPort.StatusEvent -= _serialPort_StatusEvent;
        }
        #endregion
    }

    public class SerialPorter
    {
        /// <summary>
        /// 接收数据缓存
        /// </summary>
        private string StrDataReceived = string.Empty;

        private SerialPortSetting _Setting;
        public SerialPortSetting Setting { get { return _Setting; } }
        public SerialPort SerialPort { get; private set; }
        
        public StatusEvent StatusEvent;
        public OrginDataReceived OrginDataReceived;
        public ResultReceived resultReceived;

        public SerialPorter(SerialPort serialPort)
        {
            SerialPort = serialPort;
            SetConfig(serialPort, SerialPortSetting.Instance);
            serialPort.DataReceived += _serialPort_DataReceived;
        }

        public void SetConfig(SerialPort SerialPort, SerialPortSetting setting)
        {
            bool isOpen = SerialPort.IsOpen;
            if (isOpen)
                SerialPort.Close();
            // Allow the user to set the appropriate properties.
            SerialPort.PortName = setting.PortName;// 端口
            SerialPort.BaudRate = setting.BaudRate;//波特率
            SerialPort.Parity = setting.Parity;//奇偶
            SerialPort.DataBits = setting.DataBits;//位数
            SerialPort.StopBits = setting.StopBits;//停止位
                                                   // Set the read/write timeouts
            SerialPort.ReadTimeout = 500;
            SerialPort.WriteTimeout = 500;
            //重新打开串口
            if (isOpen)
                SerialPort.Open();
            _Setting = setting;
        }

        private void _serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            var OrginData = SerialPort.ReadExisting();
            if (OrginDataReceived != null)
                OrginDataReceived(OrginData);

            StrDataReceived += OrginData;
            if (string.IsNullOrWhiteSpace(_Setting.StartChar)) return;
            var lastindex = StrDataReceived.LastIndexOf(_Setting.StartChar);
            if (lastindex <= 0) return;
            var suf = StrDataReceived.Substring(0, lastindex);
            var suflastindex = suf.LastIndexOf(_Setting.StartChar);
            if (suflastindex <= 0) return;
            var WeightData = suf.Substring(suflastindex + 1);
            StrDataReceived = StrDataReceived.Substring(lastindex);

            if (WeightData.Length > 0)
            {
                string StrWeight = string.Empty;
                char[] charArray = WeightData.ToCharArray();
                for (int i = 1; i <= charArray.Length; i++)
                {
                    StrWeight += charArray[charArray.Length - i];
                }
                if (resultReceived != null)
                {
                    resultReceived(StrWeight);
                }
            }

        }
    }
}

